const router = require('koa-router')();
const cc = require('../conCtl');
const js = require('../jsCtl');
const db = require('../dbCtl');
const pc = require('../projectCtl');
const { wechat } = require('../config.json');
const wc = require('../wechatCtl.js');

const schedule = require('node-schedule');
/**
@hostpath = http://127.0.0.1/service/auction
 */

const auctionSchedule = {
  item: {},
};


(async () => {
  await pc.initSettings();//初始化环境变量
  //获取所有正在竞拍的竞拍活动数据
  let havingAuction = await db.model('t_auction')
    .where('state=2')
    .orderBy('dt desc')
    .select();
  for (let i = 0; i < havingAuction.length; i++) {
    statAuction(await initAuctionBody(havingAuction[i]));
  }
  //获取所有即将拍卖的竞拍活动数据
  let startingAuction = await db.model('t_auction')
    .where('state=1')
    .orderBy('dt desc')
    .select();
  for (let i = 0; i < startingAuction.length; i++) {
    setTimeoutAuction(startingAuction[i].id);
  }

})();

//在pc.storeAllAuction.auctionList中构建auctionBody对象,并返回
const initAuctionBody = (auction) => {
  return new Promise(async r => {
    let auctionBody = {};
    //即将拍卖的活动逻辑
    if (auction.state != 2) await db.model('t_auction').where('id=?', auction.id).update({ state: 2 });

    pc.storeAllAuction.auctionList[auction.id] = auctionBody;
    auctionBody.curGoods = [];
    auctionBody.info = auction;//将当前拍卖活动数据存入缓存
    auctionBody.goods = await db.model('t_auction_goods a').join('t_goods b on a.goods_id=b.id').where('a.auction_id=?&&a.state=1', auction.id).field('a.*,b.name,b.details,b.starting_price,b.svaha_price,b.bid_increment,b.cost_price').select();//获取当前拍卖活动的待拍卖商品
    r(auctionBody);
  })

}

const loopInterval = 3 * 60 * 1000;//竞拍时长
// const loopInterval = 1 * 15 * 1000;//竞拍时长
// const loopInterval = 5000;//竞拍时长
// const stepInterval = 60 * 60 * 1000;//轮次间隔时长
const stepInterval = 20000;//轮次间隔时长

//立即拍卖启动器
const statAuction = async (auctionBody) => {
  console.log('开始拍卖时间:', new Date());

  pc.storeAllAuction.auctionList[auctionBody.info.id].curGoods = [];//删除正在队列中的九宫格抽奖队列

  if (!auctionBody.goods.length || auctionBody.info.state == 4) {
    //没商品了,拍卖结束
    //todo...
    await db.model('t_auction').where('id=?', auctionBody.info.id).update({ state: 3 });
    orderSchedule(auctionBody.info.id);
    delete pc.storeAllAuction.auctionList[auctionBody.info.id];//删除当前竞拍活动缓存
    console.log('拍卖结束时间:', new Date());
  } else {
    console.log('切换正在拍卖商品:', new Date());
    for (let i = 0; i < 3 && auctionBody.goods.length > 0; i++) {
      let abc = auctionBody.goods.shift();
      abc.dt = (new Date()).getTime() + loopInterval;
      abc.list = { offer_type: 0, offer_openid: "", offer_price: abc.starting_price, user: "", headurl: "" };
      abc.state = 2;
      console.log(abc.dt + 'dt1');

      timeOutPrice(abc, auctionBody.info);//定时生成机器人
      auctionBody.curGoods.push(abc);//todo... curGoods需要商品id访问
    }
    if (auctionBody.goods.length > 0) {
      auctionBody.curGoods[0].dt2 = (new Date()).getTime() + loopInterval + stepInterval
      console.log(auctionBody.curGoods[0].dt2 + 'dt2');
    }
  }

  //等待拍卖结束后
  setTimeout(async () => {
    //执行拍卖轮次结算

    //获取当前拍卖商品数据
    for (let i = 0; i < auctionBody.curGoods.length; i++) {
      let curGood = auctionBody.curGoods[i];
      curGood.state = 3;//修改缓存拍卖商品状态
      //当前竞拍商品中奖用户
      let prizeUsers = await db.model('t_auction_log a')
        .join('t_auction_goods b on a.auction_goods_id=b.auction_goods_id')
        .where('a.auction_goods_id=?', curGood.auction_goods_id)
        .field('a.*,b.goods_id,b.auction_id')
        .orderBy('a.offer_id desc,a.dt desc,a.offer_price desc')
        .shift();
      if (!js.isNullOrUndefined(prizeUsers.offer_price)){
        //修改当前竞拍商品状态以及中奖用户数据
        await db.model('t_auction_goods').where('auction_goods_id=?', curGood.auction_goods_id).update({ state: 3, final_price: prizeUsers.offer_price, winner_openid: prizeUsers.offer_openid });
      }
      if (prizeUsers.offer_type == 1) {//用户中拍
        //生成订单;用户中奖将商品状态改为已售.
        await db.startTransaction(async (tran) => {
          await tran.model('t_order').insert({ game_id: prizeUsers.auction_id, goods_id: prizeUsers.goods_id, openid: prizeUsers.offer_openid, type: 1, money: prizeUsers.offer_price, cost_price: curGood.cost_price });
          await tran.model('t_goods').where('id=?', prizeUsers.goods_id).update({ state: 3 });
          //插入中奖信息通知
          await tran.model('t_message').insert({ openid: prizeUsers.offer_openid, type: 3, title: auctionBody.info.name, message: curGood.name });
          //修改中奖用户中拍次数
          await tran.model('t_users').where('openid=?', prizeUsers.offer_openid).updateSql('winner_count=winner_count+?', 1);
        })
      } else {//机器人中拍
        let freeze_auction = pc.storeSettings.robot_auction_freeze;//机器人中拍后商品冻结时间
        //机器人中奖将商品状态改为未使用,并且设置商品冻结时间(3d);
        let time = new Date(js.parseUnitMS(new Date()) + freeze_auction * 3600);

        await db.model('t_goods').where('id=?', prizeUsers.goods_id).update({ state: 1, dt_freeze: time });
      }
    }

    //延时启动下一轮拍卖
    setTimeout(() => {
      statAuction(auctionBody);
    }, stepInterval)
  }, loopInterval);
};


//即将拍卖延时启动器
const setTimeoutAuction = async (auction_id) => {
  //获取活动数据
  let data = await db.model('t_auction').where('id=?', auction_id).shift('未找到活动');
  //清除现有定时器
  if (auctionSchedule.item[auction_id]) {
    clearInterval(auctionSchedule.item[auction_id]);
  }
  //获取活动开奖的时间
  var date = new Date(data.dt);
  //创建定时器
  auctionSchedule.item[auction_id] = schedule.scheduleJob(date, async () => {
    console.log('开始拍卖时间:', date);
    statAuction(await initAuctionBody(data));
  });
};

//用户15分钟未支付修改订单状态并且将商品状态改为未使用
const orderSchedule = async (auction_id) => {
  let time = new Date(js.parseUnitMS(new Date()) + 900);
  schedule.scheduleJob(time, async () => {
    await db.model('t_goods a').join('t_order b on a.id=b.goods_id').where('state=1&&game_id=?', auction_id).update({ state: 1 });
    //修改订单状态失效
    await db.model('t_order').where('state=1&&game_id=?', auction_id).update({ state: 6 });
    //计算并更新用户付款率
    calculation();
    //退回保证金 (未中拍和中拍已支付)
    let data = [];
    //获取当前竞拍活动中所有竞拍商品
    let auction_goods = await db.model('t_auction_goods').where('auction_id=?', auction_id).field('auction_goods_id').select();
    for (let i = 0; i < auction_goods.length; i++) {
      const goods_id = auction_goods[i];
      //当前竞拍商品中拍用户openid
      let winner_openid = await db.model('t_auction_goods').where('state=3&&auction_goods_id=?&&winner_type=0&&final_price!=0', goods_id.auction_goods_id).shift('', 'winner_openid');
      //判断当前竞拍商品有无人中拍
      if (!js.isNullOrUndefined(winner_openid.winner_openid)) {//有
        data = await db.model('t_bond').where('auction_goods_id=?&&state=1&&openid!=?', goods_id.auction_goods_id, winner_openid).select();//获取当前竞拍商品已缴纳保证金且未中拍的用户数据
        for (let i = 0; i < data.length; i++) {
          refure(data[i].trade_no);
        }
        data1 = await db.model('t_order').where('openid=?&&(state<>1&&state<>5)', winner_openid).shift();//中拍已支付
        refure(data1.trade_no);
      } else {//没有
        data = await db.model('t_bond').where('auction_goods_id=?&&state=1', goods_id.auction_goods_id).select();//获取当前竞拍商品已缴纳保证金且未中拍的用户数据
        for (let i = 0; i < data.length; i++) {
          refure(data[i].trade_no);
        }
      }
    }
  });
};

//计算并更新用户付款率
const calculation = async () => {
  console.log('计算并更新用户付款率时间:', new Date());
  let users = await db.model('t_users').select();
  for (let i = 0; i < users.length; i++) {
    let count = 0;
    const user = users[i];
    //获取用户的已支付订单数
    count = await db.model('t_order').where('openid=?&&(state>1&&state<5)', user.openid).count();
    if (user.winner_count > 0) {
      await db.model('t_users').where('openid=?', user.openid).update({ payment_rate: count / users.winner_count * 100 });
    }
  }
}

//定时器生成机器人出价
const timeOutPrice = async (goods, auction) => {
  setTimeout(async () => {
    console.log('生成机器人时间:', new Date());
    //是否活动结束
    if (auction.state == 3) {
      return;
    }
    //是否低于保护价
    //获取商品的起拍价、保护价、加价幅度
    let protective_price = await db.model('t_goods a')
      .join('t_auction_goods b on a.id=b.goods_id')
      .where('b.auction_goods_id=?', goods.auction_goods_id)
      .shift();
    //获取当前拍卖商品的当前价格
    let having_prize_price = await db.model('t_auction_log')
      .where('auction_goods_id=?', goods.auction_goods_id)
      .orderBy('offer_id desc,dt desc')
      .shift();
    //判断当前拍卖商品的当前价格有无
    if (!js.isNullOrUndefined(having_prize_price.offer_price)) {//有
      //判断当前价格是否小于保护价
      if (having_prize_price.offer_price < protective_price.protective_price) {
        makeRobot(goods, having_prize_price.offer_price + protective_price.bid_increment);//新增机器人
        timeOutPrice(goods, auction);
      } else {
        return;
      }
    } else {//无
      //当起拍价等于0时,第一手竞拍价应为加价幅度;否则第一手竞价为起拍价
      if (goods.starting_price == 0) {
        makeRobot(goods, protective_price.bid_increment);//新增机器人
      } else {
        makeRobot(goods, protective_price.starting_price);//新增机器人
      }
      timeOutPrice(goods, auction);
    }
  }, js.randomNum(8, 10) * 1000)
};

//竞拍生成机器人
const makeRobot = async (goods, offer_price) => {
  return new Promise(async r => {
    let pcGoods = await db.model('t_auction_log').where('auction_goods_id=?', goods.auction_goods_id).orderBy('dt desc').shift();
    //出价保护期间,禁止重复出价
    if (!js.isNullOrUndefined(pcGoods.dt)) {
      if (pcGoods.dt.getTime() && (new Date()).getTime() - pcGoods.dt.getTime() < 1000) {
        r();
        return;
      }
    }
    //随机获得一个机器人
    let robot = await pc.createRobot(goods.last_robot_id);
    if (robot) {
      //机器人出价
      await db.model('t_auction_log').insert({ auction_goods_id: goods.auction_goods_id, offer_type: 2, offer_openid: robot.id, offer_price: offer_price });
      goods.last_price = offer_price;
      goods.last_robot_id = robot.id;
      goods.list = { offer_type: 2, offer_openid: robot.id, offer_price: offer_price, user: robot.nick, headurl: robot.headurl };
      let count = await db.model('t_auction_log').where('auction_goods_id=?', goods.auction_goods_id).count();
      goods.count = count;
      let result = {
        code: 0,
        msg: '出价成功',
        pushMoney: offer_price,
        nick: robot.nick,
        headurl: robot.headurl,
        count,
        auction_goods_id: goods.auction_goods_id,
        state:2,
        openid:robot.id
      };
      cc.log(JSON.stringify(result))
      for (let [key, value] of Object.entries(pc.ctxs)) {
        value.websocket.send(JSON.stringify(result));
      }
    }
    r();
  });
}

const request = require('request');
const xml2js = require('xml2js');
const json2xml = new xml2js.Builder(); //json -> xml ; json2xml.buildObject(json);
const fs = require('fs');
const path = require('path');
const { rootCertificates } = require('tls');

const refure = async trade_no => {
  return new Promise(async r => {
    let trade = await db.model('t_trade').where('trade_no=?', trade_no).shift();
    //构建查询内容
    let data = {
      appid: wechat.appId,
      mch_id: wechat.pay.mch_id,
      nonce_str: Math.random().toString(36).substr(2, 15),
      out_trade_no: trade_no,
      sign_type: 'MD5',
      out_refund_no: trade_no,
      total_fee: trade.total_fee,
      refund_fee: trade.total_fee
    }
    data.sign = wc.getSign(data);
    let dataxml = json2xml.buildObject(data);
    // dataxml = dataxml.replace('root>','xml>');

    let got_result = await cc.promisify(request)({
      url: 'https://api.mch.weixin.qq.com/secapi/pay/refund',
      agentOptions: {
        cert: fs.readFileSync(path.join(__dirname, '../pem/apiclient_cert.pem')),
        key: fs.readFileSync(path.join(__dirname, '../pem/apiclient_key.pem'))
      },
      method: 'POST',
      body: dataxml
    });

    //解析返回内容
    let result = await cc.promisify(xml2js.parseString)(got_result.body, {
      explicitArray: false,
      ignoreAttrs: true
    });
    let datajson = result.xml;

    let err_msg = '';
    if (datajson.return_code != "SUCCESS") {
      err_msg = datajson.return_msg;
    } else if (datajson.result_code != "SUCCESS") {
      err_msg = datajson.err_code_des;
    }

    //查询结果为失败
    if (err_msg) { //若返回了订单号，则认为交易失败
      //失败不管
    }
    //********向微信查证订单交易情况结束,微信结果为已交易成功
    else {
      await db.model('t_trade').where('trade_no=?', datajson.out_trade_no).update({ state: 2 });//修改支付表的状态->已退款
      await db.model('t_bond').where('trade_no=?', datajson.out_trade_no).update({ state: 2 });//修改保证金表的状态->已退款
    }
    r();
  }) //promise end

};

/** 退款
###
    POST {{hostpath}}/refure
    Content-Type: application/json

    {
        "trade_no":"nq5ocz6g0z1607174416397"
    }
### */
router.post('/refure', async c => {
  refure(c.request.body.trade_no);
  cc.send(c);
});


/** 获取拍卖列表列表
###
    GET {{hostpath}}?page=1&size=30
### */
router.get('/', async c => {
  let
    page = c.query.page || 1,
    size = c.query.size || 30,
    wName = c.query.key || '';

  let model = db.model('t_auction').where('state>0');
  if (wName)
    model = model.whereExtra('&& `name` like ?', `%${wName}%`);

  let data = await model.orderBy('dt desc').select(page, size);
  let count = await model.count();

  cc.send_list(c, data, count);
});

/** 创建拍卖/编辑拍卖
###
    PUT {{hostpath}}
    Content-Type: application/json

    {
        "name":"竞拍拍卖1",
        "img":"https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTJV1PtYU4Hy5XscbWPHvic2RoSJqIuXbYK3FKtISqGAvcwRy9qFRvuiaictNYsEOG1NYibwNpNFqTMAVg/132;https://thirdwx.qlogo.cn/mmopen/vi_32/PiajxSqBRaEJKiajvARyJrQUGeybA1WHGs88U7vUWvqtq0Ue3ibDjG35fseCR7z7rjw9lkhiaLbETbxfvHOWuk6Ticw/132;https://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoGCV7UU01Bdeib9uzU3nqKibobLe80xbpqMFeSu2F6kEYcx2jicbyYwo8wOLibR0oHmEWad8WFDVwR1w/132;https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKsVHo3GJm61NcTZqnBGZwkfTjHaJA963QNNEuPjibvK6YpUV29K51UqHGpwWSvqp90vl8V60SKicWA/132",
        "dt":"2020-11-20 15:40:00"
    }
### */
router.put('/', async c => {
  js.check_params(
    !c.request.body.name && '!名称');

  let data = c.request.body;
  if (!c.request.body.id) delete data.id;

  let id = await db.model('t_auction').insertOrUpdate(data);
  setTimeoutAuction(id);

  cc.send(c, id);

});

/** 获取活动奖品列表
###
    GET {{hostpath}}/prize?page=1&size=30&id=1
### */
router.get('/prize', async c => {
  js.check_params(!c.query.id && '!活动ID');

  let data = await db.model('t_auction_goods a').join('t_goods b on a.goods_id=b.id')
    .where('a.auction_id=?&&b.state>0', c.query.id)
    .field('a.*,b.name')
    .select();
  cc.send_list(c, data);
});

/** 多商品新增
###
    POST {{hostpath}}/add_prizes
    Content-Type: application/json

    {
        "auction_id":"1",
        "goods_id":[1,2,3],
        "security":"5"
    }
### */
router.post('/add_prizes', async c => {
  js.check_params(!c.request.body.auction_id && '!拍卖ID');

  let postData = [];
  let data = c.request.body;
  for (let i = 0; i < data.goods_id.length; i++) {
    const element = data.goods_id[i];
    postData[i] = { auction_id: data.auction_id, goods_id: element, security: data.security * 100 };
  }
  await db.model('t_auction_goods').insertOrUpdate(postData, 'security=?', data.security * 100);



  cc.send(c);

});

/** 新增拍卖商品
###
    POST {{hostpath}}/add_prize
    Content-Type: application/json

    {
        "auction_goods_id":"6",
        "auction_id":"1",
        "goods_id":"1",
        "security":"0.01"
    }
### */
router.post('/add_prize', async c => {
  js.check_params(!c.request.body.auction_id && '!拍卖ID');

  let data = c.request.body;

  await db.model('t_auction').where('id=?', data.auction_id).shift('未找到拍卖活动');
  data.security *= 100;
  await db.model('t_auction_goods').Update(data);

  cc.send(c);

});

/** 删除拍卖商品
###
    DEL {{hostpath}}/prize/6
### */
router.del('/prize', async c => {
  js.check_params(!c.request.body.auction_goods_id && '!拍卖商品ID');

  let data = c.request.body;

  let state = await db.model('t_auction_goods').where('auction_goods_id=?', data.auction_goods_id).shift('未找到指定对象', 'state');
  if (state == 2 || state == 3)
    js.throwObj('进行中的竞拍商品不可删除', js.rescode.fail);

  await db.model('t_auction_goods').where('auction_goods_id=?', data.auction_goods_id).delete();

  cc.send(c);
});


/** 删除拍卖
###
    DEL {{hostpath}}
### */
router.del('/', async c => {
  js.check_params(!c.request.body.id && '!拍卖ID');

  let data = c.request.body;

  let state = await db.model('t_auction').where('id=?', data.id).shift('未找到指定对象', 'state');
  if (state == 2)
    js.throwObj('进行中的活动不可删除', js.rescode.fail);

  await db.model('t_auction').where('id=?', data.id).relyUpdate('删除失败', {
    state: 0
  });

  cc.send(c);
});


/** 手动停止
###
### */
router.post('/stop', async c => {
  js.check_params(!c.request.body.id && '!活动ID');
  //修改竞拍活动状态
  await db.model('t_auction').where('id=?', c.request.body.id).relyUpdate('停止失败', { state: 4 });
  //初始化缓存
  pc.storeAllAuction.auctionList[c.request.body.id].auction.state = 4;
  cc.send(c);
});


module.exports = router;